package com.zhong.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.zhong.auth.common.constants.AuthConstants;
import com.zhong.auth.common.enums.AuthUserStatusEnum;
import com.zhong.auth.common.enums.IsDeleteFlagEnum;
import com.zhong.auth.common.untils.RedisUntil;
import com.zhong.auth.domain.bo.AuthUserBO;
import com.zhong.auth.domain.convert.AuthUserBOConvert;
import com.zhong.auth.domain.service.AuthUserDomainService;
import com.zhong.auth.infra.basic.entity.*;
import com.zhong.auth.infra.basic.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
    @Resource
    private AuthUserService authUserService;

    @Resource
    private AuthRoleService authRoleService;

    @Resource
    private AuthUserRoleService authUserRoleService;

    @Resource
    private AuthPermissionService authPermissionService;
    @Resource
    private AuthRolePermissionService authRolePermissionService;
    @Resource
    private RedisUntil redisUntil;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        if (log.isInfoEnabled()) {
            log.info("AuthUserDomainServiceImpl.register.authUserBO：{}", JSON.toJSONString(authUserBO));
        }
        //校验用户的username查询是否已注册
        AuthUser existAuthUser = AuthUser.builder().userName(authUserBO.getUserName()).nickName(AuthConstants.DEFAULT_USER_NICK_NAME).build();
        int existCount = authUserService.queryByConditionCount(existAuthUser);
        if (existCount > 0) {
            return true;
        }
        AuthUser authUser = AuthUserBOConvert.INSTANCE.convertBOToEntity(authUserBO);
        //是否使用默认昵称
        authUser.setNickName(authUser.getNickName() == null?AuthConstants.DEFAULT_USER_NICK_NAME: authUser.getNickName());
        //用户密码不为空则加密
        String encrypt = null;
        if (StringUtils.isNoneBlank(authUser.getPassword())) {
            encrypt = SaSecureUtil.rsaEncryptByPublic(AuthConstants.PUBLIC_KEY, authUser.getPassword());
        }
        authUser.setPassword(encrypt);
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDelete(IsDeleteFlagEnum.UN_DELETE.getCode());
        Integer count = authUserService.insert(authUser);
        //建立初步的角色关联
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstants.NORMAL_USER);
        AuthRole roleResult = authRoleService.queryByCondition(authRole);
        Long roleResultId = roleResult.getId();
        Long userId = authUser.getId();
        AuthUserRole authUserRole = AuthUserRole.builder().roleId(roleResultId).userId(userId).build();
        authUserRoleService.insert(authUserRole);

        //写入将权限缓存
        //1 构建roleKey
        String roleKey = redisUntil.buildKey(AuthConstants.AUTH_ROLE_PREFIX, authUser.getUserName());
        //2.将用户信息存入缓存
        List<AuthRole> authRoleList = new LinkedList<>();
        authRoleList.add(authRole);
        redisUntil.set(roleKey, new Gson().toJson(authRoleList));
        // 3.用permissionId查询所有的roleId
        AuthRolePermission authRolePermission = AuthRolePermission.builder().roleId(roleResult.getId()).build();
        List<AuthRolePermission> authRolePermissionList = authRolePermissionService.queryCondition(authRolePermission);
        List<Long> permissionIdList = authRolePermissionList.stream().map(AuthRolePermission::getPermissionId).toList();
        // 4.根据permissionId查询权限值
        List<AuthPermission> authPermissionList = authPermissionService.queryPermissionListByIdList(permissionIdList);
        // 5.构建permissionKey并存入缓存
        String permissionKey = redisUntil.buildKey(AuthConstants.AUTH_PERMISSION_PREFIX, authUser.getUserName());
        redisUntil.set(permissionKey, new Gson().toJson(authPermissionList));
        return count > 0;
    }

    @Override
    public Boolean update(AuthUserBO authUserBO) {
        if (log.isInfoEnabled()) {
            log.info("AuthUserDomainServiceImpl.update.authUserBO：{}", JSON.toJSONString(authUserBO));
        }
        AuthUser authUser = AuthUserBOConvert.INSTANCE.convertBOToEntity(authUserBO);
        Integer count = authUserService.update(authUser);
        //任何的更新都要与缓存进行同步
        return count > 0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        if (log.isInfoEnabled()) {
            log.info("AuthUserDomainServiceImpl.delete.authUserBO：{}", JSON.toJSONString(authUserBO));
        }
        AuthUser authUser = new AuthUser();
        authUser.setId(authUserBO.getId());
        authUser.setIsDelete(IsDeleteFlagEnum.DELETE.getCode());
        Integer count = authUserService.update(authUser);
        //任何的更新都要与缓存进行同步
        return count > 0;
    }

    @Override
    public Boolean changeStatus(AuthUserBO authUserBO) {
        if (log.isInfoEnabled()) {
            log.info("AuthUserDomainServiceImpl.changeStatus.authUserBO：{}", JSON.toJSONString(authUserBO));
        }
        AuthUser authUser = new AuthUser();
        authUser.setId(authUserBO.getId());
        authUser.setStatus(authUserBO.getStatus());
        Integer count = authUserService.update(authUser);
        //任何的更新都要与缓存进行同步
        return count > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SaTokenInfo doLogin(String validCode) {
        String loginKey = redisUntil.buildKey(AuthConstants.LOGIN_PREFIX, validCode);
        String openId = redisUntil.get(loginKey);
        //缓存中如果没有openId则返回null
        if (StringUtils.isBlank(openId)) {
            return null;
        }
        register(AuthUserBO.builder().userName(openId).build());
        StpUtil.login(openId);
        return StpUtil.getTokenInfo();
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = authUserService.queryByCondition(AuthUser.builder().userName(authUserBO.getUserName()).build());
        return AuthUserBOConvert.INSTANCE.convertEntityToBO(authUser);

    }
}
